#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
	// <programme> ::= debut <seq_inst> fin FIN_FICHIER

	sauterSymCour("debut");
	Noeud* si = seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
	// <seqInst> ::= <inst> ; { <inst> ; }

	NoeudSeqInst* si = new NoeudSeqInst();
	do {
		si->ajouteInstruction(inst());
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour() == "si" || ls.getSymCour() == "tantque" || ls.getSymCour() == "repeter" || ls.getSymCour() == "pour" || ls.getSymCour() == "lire" || ls.getSymCour() == "ecrire");
	// tant que le symbole courant est un debut possible d'instruction...
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst() {
// <inst>	::= <affectation> | <instSi> | <instTq> | <instRepeter>

	if ( ls.getSymCour() == "si" )
		return instSi();
	else if ( ls.getSymCour() == "tantque" )
		return instTq();
	else if ( ls.getSymCour() == "repeter" )
		return instRepeter();
	else if ( ls.getSymCour() == "pour" )
		return instPour();
	else if ( ls.getSymCour() == "lire" )
		return instLire();
	else if ( ls.getSymCour() == "ecrire" )
		return instEcrire();
	else
		return affectation();
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression>

	testerSymCour("<VARIABLE>");
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	Noeud* exp = expression();
	return new NoeudAffectation(var,exp);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression>	::= <terme> { <opAdd> <terme> }

	Noeud* fact = terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-")
		{
		Symbole operateur = opAdd(); // on stocke le symbole de l'opérateur
		Noeud* factDroit=terme(); // lecture de l'operande droit
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud
	}
	return fact;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur()		// <facteur>	::= <entier> | <variable> | <opUnaire> <expBool> | ( <expBool> ) | <chaine>
{
	Noeud* fact=NULL;

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>" || ls.getSymCour()=="<CHAINE>") {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} else if (ls.getSymCour()=="-" || ls.getSymCour()=="non") {
		Symbole operateur = opUnaire();
		// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
		Noeud* f = expBool();
		fact = new NoeudOperateurBinaire(operateur, ts.chercheAjoute(Symbole("0")), f);
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		fact=expBool();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
	return fact;
}

Noeud* LecteurPhraseAvecArbre::terme()		// <terme>	::= <facteur> { <opMult> <facteur> }
{
	Noeud* fact = facteur();
	while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		Symbole operateur = opMult(); // on stocke le symbole de l'opérateur
		Noeud* factDroit=facteur(); // lecture de l'operande droit
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud
	}
	return fact;
}

Symbole LecteurPhraseAvecArbre::opAdd()		// <opAdd>	::= + | -
{
	Symbole operateur;
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
		{
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opAdd>");
	return operateur;
}

Symbole LecteurPhraseAvecArbre::opMult()		// <opMult>	::= * | /
{
	Symbole operateur;
	if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
		{
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opMult>");
	return operateur;
}

Noeud* LecteurPhraseAvecArbre::expBool()		// <expBool>	::= <expBoolEt> { <opBoolOu> <expBoolEt> }
{
	Noeud* fact = expBoolEt();
	while (ls.getSymCour()=="ou") {
		Symbole operateur = opBoolOu(); // on stocke le symbole de l'opérateur
		Noeud* factDroit=expBoolEt(); // lecture de l'operande droit
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud
	}
	return fact;
}

Noeud* LecteurPhraseAvecArbre::expBoolEt()	// <expBoolEt>	::= <relation> {<opBoolEt> <relation> }
{
	Noeud* fact = relation();
	while (ls.getSymCour()=="et") {
		Symbole operateur = opBoolEt(); // on stocke le symbole de l'opérateur
		Noeud* factDroit=relation(); // lecture de l'operande droit
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud
	}
	return fact;
}

Symbole LecteurPhraseAvecArbre::opBoolEt()	// <opBool>	::= et
{
	Symbole operateur;
	if (ls.getSymCour()=="et")
		{
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opBoolEt>");
	return operateur;
}  

Symbole LecteurPhraseAvecArbre::opBoolOu()	// <opBool>	::= ou    
{
	Symbole operateur;
	if (ls.getSymCour()=="ou")
		{
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opBoolOu>");
	return operateur;
}

Noeud* LecteurPhraseAvecArbre::relation()	// <relation>	::= <expression> { <opRel> <expression> }
{
	Noeud* fact = expression();
	while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<=" || ls.getSymCour()==">=" || ls.getSymCour()=="<" || ls.getSymCour()==">") {
		Symbole operateur = opRel(); // on stocke le symbole de l'opérateur
		Noeud* factDroit=expression(); // lecture de l'operande droit
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud
	}
	return fact;
}

Symbole LecteurPhraseAvecArbre::opRel()		// <opRel>	::=  == | != | < | <= | > | >=  
{
	Symbole operateur;
	if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<=" || ls.getSymCour()==">=" || ls.getSymCour()=="<" || ls.getSymCour()==">")
		{
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opRel>");
	return operateur;
}

Symbole LecteurPhraseAvecArbre::opUnaire()	// <opUnaire>	::=   - | non  
{
	Symbole operateur;
	if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
		{
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opMult>");
	return operateur;
}

//////////////////////////////////////////////////////////////////////////////////
//                            Insctructions

Noeud* LecteurPhraseAvecArbre::instSi()		// <instSi>	::= si ( <expBool> ) alors <seqInst> { sinonsi ( <expBool> ) alors <seqInst> } [ sinon <seqInst> ] finsi
{
	NoeudInstSi* noeud = NULL;
	Noeud* exp = NULL;
	Noeud* inst = NULL;
	Noeud* inst2 = NULL;
	bool sinonsi = false;
	
	if(ls.getSymCour() == "si")
		sauterSymCour("si");
	else
		{
			sinonsi = true;
			sauterSymCour("sinonsi");
		}
		
	sauterSymCour("(");
	exp = expBool();
	sauterSymCour(")");
	sauterSymCour("alors");
	inst = seqInst();
	if(ls.getSymCour() == "sinon")
	{
		sauterSymCour("sinon");
		inst2 = seqInst();
	}
	else if(ls.getSymCour() == "sinonsi")
	{
		inst2 = instSi();
	}
	else
	{
		inst2 = NULL;
	}
	if(!sinonsi)
		sauterSymCour("finsi");
	noeud = new NoeudInstSi(exp, inst, inst2);
	return noeud;

}


Noeud*  LecteurPhraseAvecArbre::instTq() {
// <instTq> ::= tantque ( <expBool> ) faire <seqInst> fintantque
	Noeud* instTq = NULL;
	Noeud* inst = NULL;
	Noeud* exp = NULL;
	
	
	if( ls.getSymCour()=="tantque" )
	{
		ls.suivant();
		if( ls.getSymCour()=="(" )
		{
			ls.suivant();
			exp = expBool();
			if( ls.getSymCour()==")" )
			{
				ls.suivant();
				if( ls.getSymCour()=="faire" )	
				{
					ls.suivant();
					inst = seqInst();
					if(ls.getSymCour()=="fintantque")
						ls.suivant();
					else
						erreur("fintantque");
				}
				else
					erreur("faire");
			}
			else
				erreur(")");
		}
		else
			erreur("(");
	}
	else
		erreur("tantque");
	
	instTq = new NoeudInstTq(exp, inst);
	return instTq;
	
}


Noeud*  LecteurPhraseAvecArbre::instRepeter() {
// <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> ) 
	
	NoeudInstRepeter* rep = NULL;
	Noeud* exp = NULL;
	Noeud* inst = NULL;
	
	sauterSymCour("repeter");
	inst = seqInst();
	sauterSymCour("jusqua");
	sauterSymCour("(");
	exp = expBool();
	sauterSymCour(")");

	
	rep = new NoeudInstRepeter(exp, inst);
	return  rep;
		
}

Noeud* LecteurPhraseAvecArbre::instPour()	// <instPour>	::= pour ( <affectation> ; <expBool> ; <affectation> ) faire <seqInst> finpour
{
	Noeud* aff = NULL;
	Noeud* aff2 = NULL;
	Noeud* exp = NULL;
	Noeud* inst = NULL;
	
	sauterSymCour("pour");
	sauterSymCour("(");
	aff = affectation();
	sauterSymCour(";");
	exp = expBool();
	sauterSymCour(";");
	aff2 = affectation();
	sauterSymCour(")");
	sauterSymCour("faire");
	inst = seqInst();
	sauterSymCour("finpour");
	
	NoeudInstPour* instPour = new NoeudInstPour(exp, inst, aff, aff2);
	return  instPour;

}

Noeud* LecteurPhraseAvecArbre::instLire()	// <instLire>	::= lire ( <variable> )
{
	NoeudInstLire* lire;
	Noeud* var = NULL;
	sauterSymCour("lire");
	sauterSymCour("(");
	if (ls.getSymCour()=="<VARIABLE>")
		var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour(")");
	lire = new NoeudInstLire(var);
	return lire;
}

Noeud* LecteurPhraseAvecArbre::instEcrire()	// <instEcrire>	::= ecrire ( <expression> | <chaine> )
{
	Noeud* exp;
	sauterSymCour("ecrire");
	sauterSymCour("(");
	if(ls.getSymCour() == "<CHAINE>")
	{
		exp = ts.chercheAjoute(ls.getSymCour() );
		ls.suivant();
		
	}
	else
		exp = expression();
	sauterSymCour(")");
		
	return new NoeudInstEcrire(exp);
	
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
